package com.thx.appserver.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xmlpull.v1.XmlPullParser;

import com.thx.common.util.AppContext;

import android.content.res.AXmlResourceParser;
import android.util.TypedValue;

/**
 * 分析APK文件，取得APK文件中的 包名、版本号
 */
public class AnalysisApk {
	/**
	 * 解压 zip 文件(apk可以当成一个zip文件)，注意不能解压 rar 文件哦，只能解压 zip 文件 解压 rar 文件 会出现
	 * java.io.IOException: Negative seek offset 异常 create date:2009- 6- 9
	 * author:Administrator
	 * 
	 * @param apkUrl
	 *            zip 文件，注意要是正宗的 zip 文件哦，不能是把 rar 的直接改为 zip 这样会出现
	 *            java.io.IOException: Negative seek offset 异常
	 * @param     type=0解析AndroidManifest.xml文件，type=1解析plugin文件
	 * @param logoUrl
	 *            图标生成的地址
	 * @throws IOException
	 * 
	 *
	 */
	public static Map<String, String> unZip(String apkUrl,int type) {
		Map<String, String> maps = new HashMap<String, String>();
		ZipFile zipFile;
		try {
			zipFile = new ZipFile(new File(apkUrl));
			Enumeration enumeration = zipFile.entries();
			ZipEntry zipEntry = null;
			while (enumeration.hasMoreElements()) {
				zipEntry = (ZipEntry) enumeration.nextElement();
				if (zipEntry.isDirectory()) {
					
				} else {
				
					if (  type==1 && zipEntry.getName().equals("assets/plugin.xml")) {
						maps=analysePlugin(zipFile,zipEntry);
					}
					if (type==0 && "AndroidManifest.xml".equals(zipEntry.getName())) {
						//maps=analyseActivity(zipFile,zipEntry);
						maps=analyseManifest(zipFile,zipEntry);
					}
					
					/*
					 * if("res/drawable-ldpi/icon.png".equals(zipEntry.getName())
					 * ){ OutputStream outputStream = new
					 * FileOutputStream(logoUrl); InputStream inputStream =
					 * zipFile.getInputStream(zipEntry); while ((length =
					 * inputStream.read(b)) > 0) outputStream.write(b, 0,
					 * length); }
					 */
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return maps;
	}

	private static String getAttributeValue(AXmlResourceParser parser, int index) {
		int type = parser.getAttributeValueType(index);
		int data = parser.getAttributeValueData(index);
		if (type == TypedValue.TYPE_STRING) {
			return parser.getAttributeValue(index);
		}
		if (type == TypedValue.TYPE_ATTRIBUTE) {
			return String.format("?%s%08X", getPackage(data), data);
		}
		if (type == TypedValue.TYPE_REFERENCE) {
			return String.format("@%s%08X", getPackage(data), data);
		}
		if (type == TypedValue.TYPE_FLOAT) {
			return String.valueOf(Float.intBitsToFloat(data));
		}
		if (type == TypedValue.TYPE_INT_HEX) {
			return String.format("0x%08X", data);
		}
		if (type == TypedValue.TYPE_INT_BOOLEAN) {
			return data != 0 ? "true" : "false";
		}
		if (type == TypedValue.TYPE_DIMENSION) {
			return Float.toString(complexToFloat(data))
					+ DIMENSION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK];
		}
		if (type == TypedValue.TYPE_FRACTION) {
			return Float.toString(complexToFloat(data))
					+ FRACTION_UNITS[data & TypedValue.COMPLEX_UNIT_MASK];
		}
		if (type >= TypedValue.TYPE_FIRST_COLOR_INT
				&& type <= TypedValue.TYPE_LAST_COLOR_INT) {
			return String.format("#%08X", data);
		}
		if (type >= TypedValue.TYPE_FIRST_INT
				&& type <= TypedValue.TYPE_LAST_INT) {
			return String.valueOf(data);
		}
		return String.format("<0x%X, type 0x%02X>", data, type);
	}

	private static String getPackage(int id) {
		if (id >>> 24 == 1) {
			return "android:";
		}
		return "";
	}

	// ///////////////////////////////// ILLEGAL STUFF, DONT LOOK :)
	public static float complexToFloat(int complex) {
		return (float) (complex & 0xFFFFFF00) * RADIX_MULTS[(complex >> 4) & 3];
	}

	private static final float RADIX_MULTS[] = { 0.00390625F, 3.051758E-005F,
			1.192093E-007F, 4.656613E-010F };
	private static final String DIMENSION_UNITS[] = { "px", "dip", "sp", "pt",
			"in", "mm", "", "" };
	private static final String FRACTION_UNITS[] = { "%", "%p", "", "", "", "",
			"", "" };

	private static Map<String, String> analyseManifest(ZipFile zipFile,ZipEntry zipEntry ){
		Map<String, String> maps = new HashMap<String, String>();
	        String result ="";
	        String tmp ="";
	        String tmp_str ="";
	        boolean flag = false;
	        
			try {
				AXmlResourceParser parser = new AXmlResourceParser();
				parser.open(zipFile.getInputStream(zipEntry));
				while (true) {
					int type = parser.next();
					if (type == XmlPullParser.END_DOCUMENT) {
						break;
					}
					switch (type) {
					case XmlPullParser.START_TAG: {
						
						if(parser.getName().equals("activity")) flag = true; else flag = false;
						for (int i = 0; i != parser.getAttributeCount(); ++i) {
							System.out.println( getAttributeValue(parser, i));
							tmp_str =  parser.getAttributePrefix(i)+":"+parser.getAttributeName(i);
							if (flag && "android:name".equals(tmp_str)) {
								tmp = getAttributeValue(parser, i);
							}
							
							if ("android.intent.action.MAIN".equals(getAttributeValue(parser, i))) {
								result = tmp;
								maps.put("activity", result);
							}
							if ("versionName".equals(parser
									.getAttributeName(i))) {
								String versionName = getAttributeValue(
										parser, i);
								maps.put("versionName", versionName);
							} else if ("versionCode".equals(parser
									.getAttributeName(i))) {
								String versionCode = getAttributeValue(
										parser, i);
								maps.put("versionCode", versionCode);
							} else if ("package".equals(parser
									.getAttributeName(i))) {
								String pack = getAttributeValue(
										parser, i);
								maps.put("package", pack);
							} else if ("minSdkVersion"
									.equals(parser
											.getAttributeName(i))) {
								String minSdkVersion = getAttributeValue(
										parser, i);
								maps.put("minSdkVersion",
										minSdkVersion);
							} else if ("targetSdkVersion"
									.equals(parser
											.getAttributeName(i))) {
								String targetSdkVersion = getAttributeValue(
										parser, i);
								maps.put("targetSdkVersion",
										targetSdkVersion);
							}
						}
					}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		System.out.println("====================="+result);
		return maps;
	}
	private static Map<String, String> analysePlugin(ZipFile zipFile,ZipEntry zipEntry ){
		Map<String, String> maps = new HashMap<String, String>();
	
			try {
				InputStream in = zipFile.getInputStream(zipEntry);
				SAXReader sr = new SAXReader();
				Document document = sr.read(in,"utf-8");
				Element root = document.getRootElement();
				
				
				List<Attribute> list  = root.attributes();
				
				for (Iterator<Attribute> iterator = list.iterator(); iterator.hasNext();) {
					Attribute attribute = (Attribute) iterator.next();
					
						maps.put(attribute.getName(), attribute.getValue());
					System.out.println(attribute.getName()+" : "+attribute.getValue());
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (DocumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		return maps;
	}
	private static Map<String, String> analyseActivity(ZipFile zipFile,ZipEntry zipEntry ){
		Map<String, String> maps = new HashMap<String, String>();
	
			try {
				InputStream in = zipFile.getInputStream(zipEntry);
				SAXReader sr = new SAXReader();
				Document document = sr.read(in,"utf-8");
				Element root = document.getRootElement();
				
				List<Attribute> list  = root.attributes();
				
				for (Iterator<Attribute> iterator = list.iterator(); iterator.hasNext();) {
					Attribute attribute = (Attribute) iterator.next();
					
						maps.put(attribute.getName(), attribute.getValue());
					System.out.println(attribute.getName()+" : "+attribute.getValue());
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (DocumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		return maps;
	}
}
